/* Printer Dumper for EPSON printers using EPSON image graphics
   Created 13.05.2002 T. Milius
   Changed 06.09.2004 T. Milius */
/* (c) Copyright 2002-2004 by Thomas Milius Stade, Germany
   Source must not be altered without agreement of the owner.
   The owner of the source is allowed to use this code inside programs without
   publishing the code of this programs. These programs may be commercial.
   Other developers can use this source freely inside own software if the source
   code of this programs is made public to same conditions like valid to this code
   and no commercial profit is taken from the programs based on this code.

   Code or parts of it are not allowed to be used within GPL code or
   similar licenses which are "infecting" other code and trying to "supersede"
   other licenses. */
/* RISCOS */

/* General EPSON Documents can be found under http://www.epsondevelopers.com/
   Part1.pdf
   Part2.pdf Page 64 and 99
   C40.pdf. Page 16 and 44

   Further information:
   C20, C40 and 480/580 Stylus Colour are using the same or a very
   similar print head and the same ink catridges. It has 3*15 pixel
   for colours Cyan Magenta Yellow and 1*48 pixel for black.
   Using the classical EPSON head steering sequences there is no
   change to find a common setting for the pixels as it is possible
   for other EPSON printer (eg. 8). So you have to use the dots/inch
   mode and the printer will map this onto the head itself.
   The original EPSON printer driver makes usage of this mode too.

   However the mode can be used at other printers too.

   The colour heads are seeming to be located one over the other
   in the order

   Cyan
   Magenta/Black
   Yellow

   May be that the internal printer software simulates this due
   to historical reasons. But Cyan is printed one head size above
   Magenta and Yellow is printed one head size below Magenta.
   Black is printed at the same level as Magenta. So the driver
   has to delay the according colours. */

/* Concept of the Dumper:

   The dumper has the following tasks:

   - It must sent printer control sequences at the right time
   - It must map sprite pixel data onto the according printer
     data sequences
   - It must interpolate Colours on the printer.

   Concept of Control sequences:

   The control sequences are following the RISCOS Dumper concept.
   Sequences are sent at the beginning and at the end of a page.
   Other sequences are horizontal/vertical positioning and passing
   the pixel data to the printer. A special feature of this dumper
   is the cellar stack calculator inside the sequences. This
   concept is described separately.

   Concept of pixel data mapping:

   Data is passed as a sprite stripe by the dumper driver to the
   dumper. At the printer there are the following facts:

   - Interlacing can be done in x and y direction
   - The printer is consisting of several heads for the colours
     (Cyan, Magenta, Yellow. Black). Unfortunately these heads
     may be not located in such a way that all the colours of a
     pixel are located at the same point. So adjustment correction
     must be done by the dumper
   - The colours of a print head must be usually passed one after
     the other but then a couple of lines will be printed at once
     printing all the colours. That means the colour buffer
     must be able to be grouped.
   - The grouped colour stripe may cover entirely different
     ranges. Eg. at the Stylus Colour Cyan Magenta Yellow and
     black will produce stripes of a high of 15 points and must
     be sent in such groups but:

     - the first 15 lines are cyan
     - the next 15 lines are Magenta and Black
     - the last 15 lines are Yellow

     So there is the necessity to split a colour stripe of
     45 point to three different groups.

   So the dumper must sort the incoming Sprite stripe data
   into a couple of buffers which are printed together as a group
   after all group members have been filled.

   The buffer structure consist of a couple of pixel lines
   grouped by colour, printing group and interlace level.
   The number of pixel lines inside such a grouping is determined
   by the lines of the print head (15 at the EPSON Stylus Color 580).

   Each buffer has a row where it starts and a flag per line
   whether the line has been filled with data or not. The dumper has
   a sprite row counter. If the row of buffer added with the number
   of lines inside the buffer is less than the actual sprite row number
   the buffer has been filled. It is passed towards the printer then
   and the buffer is free for usage again beginning a fixed amount
   of rows after its old position.

   Concept of Colour interpolation:

   Some printers are having unfortunately different number of pixel
   per print head. Eg. the EPSON Stylus Color 580 has 48 dots on
   its black head but only 15 dots on every of its colour heads.
   And these 3 Colour head are arranged under each other so that
   3*15 dots but in different colours can be printed in one head
   movement. EPSON however provides a special printing mode which
   manages the exact black and colour mapping to the dots inside
   the printer. This mode includes also a concept to reduce the
   line effects which can occur by very small differences at
   the dot distance of the print heads. The mode also allows
   you to give pixel a different dot size on the paper. Actually
   4 dot sizes per colour are allowed:

   - No dot
   - dot of size 1
   - dot of size 2
   - dot of size 4

   This is used to realize 4 different colour intensities. On the
   other side the print resolution is reduced. So the EPSON
   Stylus Color 580 can cope with resolutions of 360*120 dots per
   inch. But with the dot size above and y interlacing (3 vertical
   interlaces in a feed in distances of 14/17/14 dots) the effect
   is similar to a 720 * 720 dot per inch resolution.
   Indeed the higher resolutions are used to interpolate more
   colours but this can be achieved also using other methods with
   lower resolution. The EPSON concept gives you 4*4*4 colours
   and 4 kinds of black. Black is covering the other colours so
   you can't mix it with the colours. But with interlacing and
   dithering you are able to increase the number of colours of
   your prints a lot.

   The dithering concept is described inside a separate module
   in more details. */
/* To Do:
   - error handling language independent
   - filling of remaining environment variables
   - horizontal interlacing
   - 8 Bit Colour mode
   - 8 Bit Colour separation mode
   - arbitrary number of stages
   - graphics output compression */

/* !!!!!!!!!! libraries !!!!!!!!!! */
/* ---------- ANSI-C ---------- */
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* ---------- RISCOS ---------- */
#include <kernel.h>
#include <swis.h>

/* ---------- own ---------- */
#include "mem_manag.h"
#include "settings.h"
#include "pcntrl_strings.h"
#include "colour_groups.h"
#include "rngsearch.h"
#include "sprite_output.h"

/* !!!!!!!!!! CMUNGE/CHMG-Code Declarations !!!!!!!!!! */
extern int printer_driver_handler_adap(_kernel_swi_regs *regs, void *pw);

/* !!!!!!!!!! definitions !!!!!!!!!! */
/* to clarify reading */
#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

//#define DEBUG_MODE

/* Dumper array sizes */
#define MAX_CATRIDGES             10
#define MAX_VERTICAL_INTERLACES   3
#define MAX_HORIZONTAL_INTERLACES 3

/* On 128 Bytes there can be one size byte.
   Approx constant for DIN A0 2880 dpi */
#define WORST_CASE_COMPRESSION_OFFSET 1024

/* Attention: Not registered */
#define PRINTER_DUMPER_NUMBER 22

/* RISCOS PDumper Actions */
#define PDUMPERREASON_SETDRIVER 0
#define PDUMPERREASON_OUTPUTDUMP 1
#define PDUMPERREASON_COLOURSET 2
#define PDUMPERREASON_STARTPAGE 3
#define PDUMPERREASON_ENDPAGE 4
#define PDUMPERREASON_STARTJOB 5
#define PDUMPERREASON_ABORTJOB 6
#define PDUMPERREASON_MISCOP 7

#define SERVICE_PDUMPERSTARTING 0x00000066
#define SERVICE_PDUMPERDYING 0x00000067

#define PRINTER_DRIVER 7

/* !!!!!!!!!! data structures !!!!!!!!!! */
/* print job specific data structure */
struct job_struct {
#ifdef DEBUG_MODE
int magic1;
int output_file;
#endif
/* Data of a printer dumper instance */
int dynamic_area;
/* printer depending tables. */
/* No dynamic allocation because it only very small size
   even in worst case. */
int colour_horizontal_adjustment[MAX_CATRIDGES];
int colour_vertical_adjustment[MAX_CATRIDGES];
int catridge_position[MAX_CATRIDGES];
struct colour_search_struct colour_search;
long loaded_calibration;
/* Render acceleration */
unsigned long paper_colour;
unsigned long paper_colour_compare;
unsigned long paper_colour_pattern;
unsigned long full_black;
unsigned long full_black_compare;
unsigned long full_black_pattern;
int black_mode_flag;
/* Sequences */
struct command_sequence_struct page_start;
struct command_sequence_struct page_end;
struct command_sequence_struct line_return;
struct command_sequence_struct *line_pass;
struct command_sequence_struct *line_end;
struct cellar_stack_variable_struct environment;
/* Data of a print job */
/* absolute line position on the printer */
int act_page_line;
unsigned long maximal_bytes_per_line_storage;
/* line for colour adaptation */
unsigned long *preconverted_line;
int maximal_preconv_width;
/* Printer Bitmap stripes */
int *first_page_line;
unsigned long *max_stripe_usage_position;
unsigned char *stripe_line_filled;
unsigned char *stripe;
/* Compression */
unsigned char *compressed_stripe;
unsigned long *compressed_stripe_size;
/* Sprite output */
struct sprite_output_struct sprite_output;
#ifdef DEBUG_MODE
int magic2;
#endif
};

/* General dumper data */
struct {
#ifdef DEBUG_MODE
int magic1;
int last_op;
#endif
/* Bigger data of a printer dumper driver */
int dynamic_area;
/* RISCOS error handling */
_kernel_oserror error_os;
/* Actual printer control sequences for later copy into job data */
struct command_sequence_struct printer_properties;
struct command_sequence_struct page_start;
struct command_sequence_struct page_end;
struct command_sequence_struct line_return;
struct command_sequence_struct line_pass[MAX_CATRIDGES];
struct command_sequence_struct line_end[MAX_VERTICAL_INTERLACES];
/* printing system information for later copy into job data */
long no_of_interlaces_vertical;
long no_of_interlaces_horizontal;
long dots_of_print_head;
long no_of_stages;
/* various */
long job_number;
/* Dither Information */
int *dither_line_offset;
int stack_trace_flag;
#ifdef DEBUG_MODE
int magic2;
#endif
} common;

/* !!!!!!!!!! support functions !!!!!!!!!! */
/* ---------- Address handling ---------- */
int *get_first_page_line_address(struct job_struct *act_job,
                                 int stage,
                                 int vertical_interlace,
                                 int horizontal_interlace,
                                 int catridge)
{
unsigned long base;

#ifdef DEBUG_MODE
if ((stage < 0) ||
    (stage >= act_job->environment.dumper.no_of_stages) ||
    (vertical_interlace < 0) ||
    (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical) ||
    (horizontal_interlace < 0) ||
    (horizontal_interlace >= 1) ||
    (catridge < 0) ||
    (catridge >= act_job->environment.dumper.no_of_printer_catridges)) {
  _kernel_swi_regs regs;

  if ((stage < 0) ||
      (stage >= act_job->environment.dumper.no_of_stages)) {
    sprintf(common.error_os.errmess, "Array violation first page line. Stage is %d (Max %ld)", stage, act_job->environment.dumper.no_of_stages);
    }
  if ((vertical_interlace < 0) ||
      (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical)) {
    sprintf(common.error_os.errmess, "Array violation first page line. Vertical interlace is %d (Max %ld)", vertical_interlace, act_job->environment.printing_system.no_of_interlaces_vertical);
    }
  if ((horizontal_interlace < 0) ||
      (horizontal_interlace >= 1)) {
    sprintf(common.error_os.errmess, "Array violation first page line. Horizontal interlace is %d (Max %d)", horizontal_interlace, 1);
    }
  if ((catridge < 0) ||
      (catridge >= act_job->environment.dumper.no_of_printer_catridges)) {
    sprintf(common.error_os.errmess, "Array violation first page line. Catridge is %d (Max %ld)", catridge, act_job->environment.dumper.no_of_printer_catridges);
    }
  regs.r[0]=2;
  regs.r[1]=act_job->output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return (int *) act_job->first_page_line;
  }
#endif
base=(unsigned long) act_job->first_page_line +
     (act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*act_job->environment.printing_system.no_of_interlaces_vertical*stage +
      act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*vertical_interlace +
      act_job->environment.dumper.no_of_printer_catridges*horizontal_interlace +
      catridge) * sizeof(int);
return (int *) base;
}

unsigned long *get_max_stripe_usage_position_address(struct job_struct *act_job,
                                                     int stage,
                                                     int vertical_interlace,
                                                     int horizontal_interlace,
                                                     int catridge)
{
unsigned long base;

#ifdef DEBUG_MODE
if ((stage < 0) ||
    (stage >= act_job->environment.dumper.no_of_stages) ||
    (vertical_interlace < 0) ||
    (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical) ||
    (horizontal_interlace < 0) ||
    (horizontal_interlace >= 1) ||
    (catridge < 0) ||
    (catridge >= act_job->environment.dumper.no_of_printer_catridges)) {
  _kernel_swi_regs regs;

  if ((stage < 0) ||
      (stage >= act_job->environment.dumper.no_of_stages)) {
    sprintf(common.error_os.errmess, "Array violation max stripe usage position. Stage is %d (Max %ld)", stage, act_job->environment.dumper.no_of_stages);
    }
  if ((vertical_interlace < 0) ||
      (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical)) {
    sprintf(common.error_os.errmess, "Array violation max stripe usage position. Vertical interlace is %d (Max %ld)", vertical_interlace, act_job->environment.printing_system.no_of_interlaces_vertical);
    }
  if ((horizontal_interlace < 0) ||
      (horizontal_interlace >= 1)) {
    sprintf(common.error_os.errmess, "Array violation max stripe usage position. Horizontal interlace is %d (Max %d)", horizontal_interlace, 1);
    }
  if ((catridge < 0) ||
      (catridge >= act_job->environment.dumper.no_of_printer_catridges)) {
    sprintf(common.error_os.errmess, "Array violation max stripe usage position. Catridge is %d (Max %ld)", catridge, act_job->environment.dumper.no_of_printer_catridges);
    }
  regs.r[0]=2;
  regs.r[1]=act_job->output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return (unsigned long *) act_job->max_stripe_usage_position;
  }
#endif
base=(unsigned long) act_job->max_stripe_usage_position +
     (act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*act_job->environment.printing_system.no_of_interlaces_vertical*stage +
      act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*vertical_interlace +
      act_job->environment.dumper.no_of_printer_catridges*horizontal_interlace +
      catridge) * sizeof(unsigned long);
return (unsigned long *) base;
}

unsigned char *get_stripe_line_filled_address(struct job_struct *act_job,
                                              int stage,
                                              int vertical_interlace,
                                              int horizontal_interlace,
                                              int catridge,
                                              int row)
{
unsigned long base;

#ifdef DEBUG_MODE
if ((stage < 0) ||
    (stage >= act_job->environment.dumper.no_of_stages) ||
    (vertical_interlace < 0) ||
    (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical) ||
    (horizontal_interlace < 0) ||
    (horizontal_interlace >= 1) ||
    (catridge < 0) ||
    (catridge >= act_job->environment.dumper.no_of_printer_catridges) ||
    (row < 0) ||
    (row >= act_job->environment.printing_system.dots_of_print_head)) {
  _kernel_swi_regs regs;

  if ((stage < 0) ||
      (stage >= act_job->environment.dumper.no_of_stages)) {
    sprintf(common.error_os.errmess, "Array violation stripe line filled. Stage is %d (Max %ld)", stage, act_job->environment.dumper.no_of_stages);
    }
  if ((vertical_interlace < 0) ||
      (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical)) {
    sprintf(common.error_os.errmess, "Array violation stripe line filled. Vertical interlace is %d (Max %ld)", vertical_interlace, act_job->environment.printing_system.no_of_interlaces_vertical);
    }
  if ((horizontal_interlace < 0) ||
      (horizontal_interlace >= 1)) {
    sprintf(common.error_os.errmess, "Array violation stripe line filled. Horizontal interlace is %d (Max %d)", horizontal_interlace, 1);
    }
  if ((catridge < 0) ||
      (catridge >= act_job->environment.dumper.no_of_printer_catridges)) {
    sprintf(common.error_os.errmess, "Array violation stripe line filled. Catridge is %d (Max %ld)", row, act_job->environment.dumper.no_of_printer_catridges);
    }
  if ((row < 0) ||
      (row >= act_job->environment.printing_system.dots_of_print_head)) {
    sprintf(common.error_os.errmess, "Array violation stripe line filled. Row is %d (Max %ld)", row, act_job->environment.printing_system.dots_of_print_head);
    }
  regs.r[0]=2;
  regs.r[1]=act_job->output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return (unsigned char *) act_job->stripe_line_filled;
  }
#endif
base=(unsigned long) act_job->stripe_line_filled +
     (act_job->environment.printing_system.dots_of_print_head*act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*act_job->environment.printing_system.no_of_interlaces_vertical*stage +
      act_job->environment.printing_system.dots_of_print_head*act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*vertical_interlace +
      act_job->environment.printing_system.dots_of_print_head*act_job->environment.dumper.no_of_printer_catridges*horizontal_interlace +
      act_job->environment.printing_system.dots_of_print_head*catridge +
      row) * sizeof(unsigned char);
return (unsigned char *) base;
}

unsigned char *get_stripe_address(struct job_struct *act_job,
                                  int stage,
                                  int vertical_interlace,
                                  int horizontal_interlace,
                                  int catridge,
                                  int row)
{
unsigned long base;

#ifdef DEBUG_MODE
if ((stage < 0) ||
    (stage >= act_job->environment.dumper.no_of_stages) ||
    (vertical_interlace < 0) ||
    (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical) ||
    (horizontal_interlace < 0) ||
    (horizontal_interlace >= 1) ||
    (catridge < 0) ||
    (catridge >= act_job->environment.dumper.no_of_printer_catridges) ||
    (row < 0) ||
    (row >= act_job->environment.printing_system.dots_of_print_head)) {
  _kernel_swi_regs regs;

  if ((stage < 0) ||
      (stage >= act_job->environment.dumper.no_of_stages)) {
    sprintf(common.error_os.errmess, "Array violation stripe. Stage is %d (Max %ld)", stage, act_job->environment.dumper.no_of_stages);
    }
  if ((vertical_interlace < 0) ||
      (vertical_interlace >= act_job->environment.printing_system.no_of_interlaces_vertical)) {
    sprintf(common.error_os.errmess, "Array violation stripe. Vertical interlace is %d (Max %ld)", vertical_interlace, act_job->environment.printing_system.no_of_interlaces_vertical);
    }
  if ((horizontal_interlace < 0) ||
      (horizontal_interlace >= 1)) {
    sprintf(common.error_os.errmess, "Array violation stripe. Horizontal interlace is %d (Max %d)", horizontal_interlace, 1);
    }
  if ((catridge < 0) ||
      (catridge >= act_job->environment.dumper.no_of_printer_catridges)) {
    sprintf(common.error_os.errmess, "Array violation stripe. Catridge is %d (Max %ld)", row, act_job->environment.dumper.no_of_printer_catridges);
    }
  if ((row < 0) ||
      (row >= act_job->environment.printing_system.dots_of_print_head)) {
    sprintf(common.error_os.errmess, "Array violation stripe. Row is %d (Max %ld)", row, act_job->environment.printing_system.dots_of_print_head);
    }
  regs.r[0]=2;
  regs.r[1]=act_job->output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return (unsigned char *) act_job->stripe;
  }
#endif
base=(unsigned long) act_job->stripe +
     (act_job->environment.printing_system.dots_of_print_head*act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*act_job->environment.printing_system.no_of_interlaces_vertical*stage +
      act_job->environment.printing_system.dots_of_print_head*act_job->environment.dumper.no_of_printer_catridges*act_job->environment.printing_system.no_of_interlaces_horizontal*vertical_interlace +
      act_job->environment.printing_system.dots_of_print_head*act_job->environment.dumper.no_of_printer_catridges*horizontal_interlace +
      act_job->environment.printing_system.dots_of_print_head*catridge +
      row)*act_job->maximal_bytes_per_line_storage*sizeof(unsigned char);
return (unsigned char *) base;
}

unsigned char *get_compressed_stripe_address(struct job_struct *act_job,
                                             int row)
{
unsigned long base;

#ifdef DEBUG_MODE
if ((row < 0) ||
    (row >= act_job->environment.printing_system.dots_of_print_head)) {
  _kernel_swi_regs regs;

  if ((row < 0) ||
      (row >= act_job->environment.printing_system.dots_of_print_head)) {
    sprintf(common.error_os.errmess, "Array violation compressed stripe. Row is %d (Max %ld)", row, act_job->environment.printing_system.dots_of_print_head);
    }
  regs.r[0]=2;
  regs.r[1]=act_job->output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return (unsigned char *) act_job->stripe;
  }
#endif
base=(unsigned long) act_job->compressed_stripe +
      row*(act_job->maximal_bytes_per_line_storage + WORST_CASE_COMPRESSION_OFFSET)*
      sizeof(unsigned char);
return (unsigned char *) base;
}

/* ---------- sent data to printer ---------- */
/* Flushes a given stage/interlace buffer content to the printer */
int flush_data(struct job_struct *act_job,
               int act_stage,
               int act_v_interlace,
               int output_file)
{
unsigned char *c;
unsigned char *last_position;
unsigned char *act_compression_position;
unsigned char *compression_head_position;
int byte_counter;
int act_flush_row;
int act_catridge;
_kernel_swi_regs regs;

/* Flush content of printer buffer to file */
/* Set up the environment */
act_job->environment.job_state.act_stage=act_stage;
act_job->environment.job_state.act_interlace_vertical=act_v_interlace;
act_job->environment.job_state.act_interlace_horizontal=0;
for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
  if ((*get_max_stripe_usage_position_address(act_job,
                                              act_stage,
                                              act_v_interlace,
                                              0,
                                              act_catridge)) > 0) {
    /* Set up the environment */
    act_job->environment.job_state.byte_data_amount=*get_max_stripe_usage_position_address(act_job,
                                                                                           act_stage,
                                                                                           act_v_interlace,
                                                                                           0,
                                                                                           act_catridge)*act_job->environment.printing_system.dots_of_print_head;
    act_job->environment.job_state.bytes_per_line_filled=*get_max_stripe_usage_position_address(act_job,
                                                                                                act_stage,
                                                                                                act_v_interlace,
                                                                                                0,
                                                                                                act_catridge);
    for (act_flush_row=0; act_flush_row < act_job->environment.printing_system.dots_of_print_head; act_flush_row++) {
      /* Dummy white lines must be generated at here, because this
         information is used for compression */
      if ((*get_stripe_line_filled_address(act_job,
                                           act_stage,
                                           act_v_interlace,
                                           0,
                                           act_catridge,
                                           act_flush_row)) != TRUE) {
        /* Generate a dummy blank line. Lines are either filled correctly over all pixel or are not
           generated at all.  */
        c=get_stripe_address(act_job,
                             act_stage,
                             act_v_interlace,
                             0,
                             act_catridge,
                             act_flush_row);
        last_position=c + *get_max_stripe_usage_position_address(act_job,
                                                                 act_stage,
                                                                 act_v_interlace,
                                                                 0,
                                                                 act_catridge);
        while (c < last_position) {
          *c=0;
          c++;
          }
        }
      else {
        /* Reset row fill information */
        *get_stripe_line_filled_address(act_job,
                                        act_stage,
                                        act_v_interlace,
                                        0,
                                        act_catridge,
                                        act_flush_row)=FALSE;
        }
      /* Compression must be generated at here to allow determination
         of total compressed byte size. */
      if (act_job->environment.dumper.compression_format == 1) {
        /* Run length encoding (RLE) compression:

           0-127   - So much bytes + 1 of data will follow
           128-255 - So often following byte will repeat

           Start mode:
           Look into the first two Bytes.
           If there is only one Byte then way of proceeding
           doesn't matter.
           If the two Bytes are identical start with repeating
           mode.
           If they are different start with data mode.

           Repeating Mode:
           Loop until a Byte is found which differs from
           that one before or maximum of repeating bytes
           has been reached. After that change into
           start mode.

           data mode:
           Loop until a Byte is found which is the same than
           that one before or maximum of different bytes
           has been reached. After that change into
           start mode. */
        act_compression_position=get_compressed_stripe_address(act_job,
                                                               act_flush_row);
        c=get_stripe_address(act_job,
                             act_stage,
                             act_v_interlace,
                             0,
                             act_catridge,
                             act_flush_row);
        last_position=c + *get_max_stripe_usage_position_address(act_job,
                                                                 act_stage,
                                                                 act_v_interlace,
                                                                 0,
                                                                 act_catridge);
        while (c < last_position) {
          /* Start mode.
             Check whether there is more than one byte left. */
          if (c < (last_position - 1)) {
            /* Note the beginning of the new sequence
               in output buffer. */
            compression_head_position=act_compression_position;
            /* Space for mode byte */
            act_compression_position++;
            /* Determine mode of new sequence.
               At least two bytes must be equal. */
            if (*c == *(c + 1)) {
              /* Repeating Mode */
              byte_counter=1;
              /* Store repeated byte */
              *act_compression_position=*c;
              act_compression_position++;
              /* Check whether next byte is still the same.
                 Upto 128 Bytes. */
              while ((c < (last_position - 1)) &&
                     (*c == *(c + 1)) &&
                     (byte_counter < 128)) {
                byte_counter++;
                c++;
                }
              /* Store number of bytes */
              *compression_head_position=(~((byte_counter - 2) & 0x7F));
              c++;
              }
            else {
              /* Data mode */
              byte_counter=0;
              /* Check whether next byte is still not the same.
                 Upto 128 Bytes. */
              while ((c < (last_position - 1)) &&
                     (*c != *(c + 1)) &&
                     (byte_counter < 128)) {
                *act_compression_position=*c;
                act_compression_position++;
                byte_counter++;
                c++;
                }
              if ((c == (last_position - 1)) &&
                  (byte_counter < 128)) {
                *act_compression_position=*c;
                act_compression_position++;
                byte_counter++;
                c++;
                }
              *compression_head_position=(byte_counter - 1);
              }
            }
          else {
            /* Last byte. Encoded as data sequence */
            *act_compression_position=0;
            act_compression_position++;
            *act_compression_position=*c;
            act_compression_position++;
            c++;
            }
          }
        act_job->compressed_stripe_size[act_flush_row]=act_compression_position - get_compressed_stripe_address(act_job,
                                                                                                                act_flush_row);
        }
      }
    /* Sent colour dependent graphics control sequence to printer */
    if (sent_control_string(&act_job->line_pass[act_catridge],
                            output_file,
                            &act_job->environment) &&
        (act_job->environment.dumper.printer_mode == 0)) {
      for (act_flush_row=0; act_flush_row < act_job->environment.printing_system.dots_of_print_head; act_flush_row++) {
        if (act_job->environment.dumper.compression_format == 1) {
          /* Run Length Encoded (RLE) data. */
          regs.r[0]=2;
          regs.r[1]=output_file;
          regs.r[2]=(int) get_compressed_stripe_address(act_job,
                                                        act_flush_row);
          regs.r[3]=act_job->compressed_stripe_size[act_flush_row];
          _kernel_swi(OS_GBPB, &regs, &regs);
          }
        else {
          /* Uncompressed Data */
          /* Sent the colour specific graphic pixel data to printer */
          regs.r[0]=2;
          regs.r[1]=output_file;
          regs.r[2]=(int) get_stripe_address(act_job,
                                             act_stage,
                                             act_v_interlace,
                                             0,
                                             act_catridge,
                                             act_flush_row);
          regs.r[3]=*get_max_stripe_usage_position_address(act_job,
                                                           act_stage,
                                                           act_v_interlace,
                                                           0,
                                                           act_catridge);
          _kernel_swi(OS_GBPB, &regs, &regs);
          }
        }
      }
    else {
      /* Send no data if control string caused problems however
         or if mode does not allow sending of data */
      for (act_flush_row=0; act_flush_row < act_job->environment.printing_system.dots_of_print_head; act_flush_row++) {
        /* Reset row fill information */
        *get_stripe_line_filled_address(act_job,
                                        act_stage,
                                        act_v_interlace,
                                        0,
                                        act_catridge,
                                        act_flush_row)=FALSE;
        }
      }
    /* Reset max_usage position */
    *get_max_stripe_usage_position_address(act_job,
                                           act_stage,
                                           act_v_interlace,
                                           0,
                                           act_catridge)=0;
    }
  *get_first_page_line_address(act_job,
                               act_stage,
                               act_v_interlace,
                               0,
                               act_catridge)=*get_first_page_line_address(act_job,
                                                                          act_stage,
                                                                          act_v_interlace,
                                                                          0,
                                                                          act_catridge) +
                                             act_job->environment.dumper.no_of_stages*act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head;
  }
/* Sent line end control string depending on interlace to printer */
/* RISC OS Dumper supports only a limited number of vertical interlace strings.
   So dynamic sequences must be used for emulation of more interlaces */
sent_control_string(&act_job->line_end[act_v_interlace%MAX_VERTICAL_INTERLACES],
                    output_file,
                    &act_job->environment);
return TRUE;
}

/* !!!!!!!!!! functions !!!!!!!!!! */
int set_driver(unsigned char *printer_definitions,
               unsigned char *extended_strings,
               unsigned long configuration_word)
{
int i;
struct command_sequence_struct h;

/* Set up the environment */
common.no_of_interlaces_vertical=*(printer_definitions + 1) + 1;
common.no_of_interlaces_horizontal=*(printer_definitions +2) + 1;
common.dots_of_print_head=*printer_definitions;
/* Definition:
   Dump height should be as big as possible and the other side it can
   be maximum 255. It is evaluated by the printing system. On the other
   in information about stages shpuld be passed.
   Definition is:

   (Dump height/Dump Depth)*2=No of stages

   because including the interlaces would lead to problems at modern
   print heads with 60 dots with maximal value of 255. */
common.no_of_stages=*(printer_definitions + 14);
common.no_of_stages=(common.no_of_stages/common.dots_of_print_head)*2;
/* Zero skip contains printer specific properties */
get_control_string(printer_definitions,
                   PRINTER_STRING_ZERO_SKIP,
                   &common.printer_properties,
                   extended_strings,
                   configuration_word);
/* Unfortunately at some machines like EPSON Page_Start
   is not long enough. Not with the real space but inside the
   !PrinEdit fields. So Set_Lines is used for that purpose
   and both strings are merged together */
get_control_string(printer_definitions,
                   PRINTER_STRING_SET_LINES,
                   &common.page_start,
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_PAGE_START,
                   &h,
                   extended_strings,
                   configuration_word);
for (i=0; i < h.length; i++) {
  common.page_start.sequence[common.page_start.length]=h.sequence[i];
  common.page_start.length++;
  }
get_control_string(printer_definitions,
                   PRINTER_STRING_PAGE_END,
                   &common.page_end,
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_RETURN,
                   &common.line_return,
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_START_MC_BL,
                   &common.line_pass[0],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C1_BL,
                   &common.line_pass[1],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C2_BL,
                   &common.line_pass[2],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C3_BL,
                   &common.line_pass[3],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C4_BL,
                   &common.line_pass[4],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_START_MC_AL,
                   &common.line_pass[5],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C1_AL,
                   &common.line_pass[6],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C2_AL,
                   &common.line_pass[7],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C3_AL,
                   &common.line_pass[8],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_PASS_C4_AL,
                   &common.line_pass[9],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_END_I1,
                   &common.line_end[0],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_END_I2,
                   &common.line_end[1],
                   extended_strings,
                   configuration_word);
get_control_string(printer_definitions,
                   PRINTER_STRING_LINE_END_I3,
                   &common.line_end[2],
                   extended_strings,
                   configuration_word);
return TRUE;
}

int output_dump(struct job_struct *act_job,
                int output_file,
                unsigned char *line_pos,
                int line_length,
                int line_size,
                int stripe_lines,
                int stripe_type)
{
int h;
int act_line;
int act_stage;
int act_v_interlace;
int act_catridge;
int act_catridge_pixel_shift;
int act_strip_line;
int max_line_pos;
/* Dither speed up */
unsigned char paper_colour_c;
unsigned short paper_colour_s;
unsigned long paper_colour_l;
unsigned char full_black_c;
unsigned short full_black_s;
unsigned long full_black_l;
/* Sprite source */
unsigned char *pixel_pos_c;
unsigned short *pixel_pos_s;
unsigned long *pixel_pos_l;
unsigned char *line_end_c;
unsigned short *line_end_s;
unsigned long *line_end_l;
/* Preconversion */
unsigned long pre_conv_usage_pattern;
unsigned long *pre_conv_pos;
unsigned long *pre_conv_end;
unsigned long pixel_mask;
/* Target pixel map */
unsigned char *stripe_pos;
int sub_pos;
int act_pos;

if (!act_job) {
  return FALSE;
  }
#ifdef DEBUG_MODE
if ((act_job->magic1!=23456) ||
    (act_job->magic2!=78901)) {
  _kernel_swi_regs regs;

  sprintf(common.error_os.errmess, "job violation output %d %d", act_job->magic1, act_job->magic2);
  regs.r[0]=2;
  regs.r[1]=output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return FALSE;
  }
#endif
/* Protection of preconverter buffer */
if (line_length > act_job->maximal_preconv_width) {
  line_length=act_job->maximal_preconv_width;
  }
/* Convert line by line of the recieved sprite stripe into dumper buffers */
pixel_mask=0xFFFFFFFF>>(32 - act_job->environment.dumper.bits_per_printer_pixel);
switch(stripe_type) {
  case 0: {
    /* Monochrom Black/White 1 Bit */
    /* Line size remains unchanged. No need to start at a word boundary */
    }
  break;
  case 1: {
    /* Greyscaled 8 Bit */
    /* Line size remains unchanged. No need to start at a word boundary */
    }
  break;
  case 2: {
    /* Colour 8 bit */
    /* Line size remains unchanged. No need to start at a word boundary */
    }
  break;
  case 3: {
    /* Colour separation 8 bit per Colour */
    /* Line size remains unchanged. No need to start at a word boundary */
    }
  break;
  case 4: {
    /* Colour 16 bit */
    /* No need to start at a word boundary */
    line_size*=2;
    }
  break;
  case 5: {
    /* Colour 32 bit */
    line_size*=4;
    }
  break;
  }
/* Note that every pixel in a line is set! However
   it is only printed until most right not blank pixel. */
for (act_line=0; act_line < stripe_lines; act_line++) {
  start_dithering(&act_job->colour_search);
  /* Pre converting including Black correction and Dithering */
  pre_conv_pos=act_job->preconverted_line;
  /* Assume no Catridges used */
  pre_conv_usage_pattern=0x00000000;
  switch(stripe_type) {
    case 0: {
      /* Monochrom Black/White 1 Bit */
      line_end_c=line_pos + line_length;
      for (pixel_pos_c=line_pos; pixel_pos_c < line_end_c; pixel_pos_c++) {
        for (sub_pos=0; sub_pos<8; sub_pos++) {
          if (((*pixel_pos_c) & (0x01<<sub_pos)) != 0) {
            /* 1 = White = paper colour */
            *pre_conv_pos=act_job->paper_colour_pattern;
            }
          else {
            *pre_conv_pos=act_job->full_black_pattern;
            }
          /* Update Catridge usage */
          pre_conv_usage_pattern|=*pre_conv_pos;
          pre_conv_pos++;
          }
        }
      /* Move to next stripe line */
      line_pos+=line_size;
      }
    break;
    case 1: {
      /* Greyscaled 8 Bit */
      paper_colour_c=act_job->paper_colour_compare;
      full_black_c=act_job->full_black_compare;
      line_end_c=line_pos + line_length;
      for (pixel_pos_c=line_pos; pixel_pos_c < line_end_c; pixel_pos_c++) {
        if ((*pixel_pos_c) == paper_colour_c) {
          *pre_conv_pos=act_job->paper_colour_pattern;
          }
        else if ((*pixel_pos_c) == full_black_c) {
          *pre_conv_pos=act_job->full_black_pattern;
          }
        else {
          *pre_conv_pos=find_best_colour(&act_job->colour_search,
                                         *pixel_pos_c,
                                         *pixel_pos_c,
                                         *pixel_pos_c,
                                         (int) pre_conv_pos>>2,
                                         act_job->paper_colour_pattern,
                                         act_job->environment.dumper.printer_mode,
                                         act_job->black_mode_flag);
          }
        /* Update Catridge usage */
        pre_conv_usage_pattern|=*pre_conv_pos;
        pre_conv_pos++;
        }
      /* Move to next stripe line */
      line_pos+=line_size;
      }
    break;
    case 2: {
      /* Colour 8 bit */
      paper_colour_c=act_job->paper_colour_compare;
      full_black_c=act_job->full_black_compare;
      line_end_c=line_pos + line_length;
      for (pixel_pos_c=line_pos; pixel_pos_c < line_end_c; pixel_pos_c++) {
        if ((*pixel_pos_c) == paper_colour_c) {
          *pre_conv_pos=act_job->paper_colour_pattern;
          }
        else if ((*pixel_pos_c) == full_black_c) {
          *pre_conv_pos=act_job->full_black_pattern;
          }
        else {
          *pre_conv_pos=find_best_colour(&act_job->colour_search,
                                         ((*pixel_pos_c) & 0x0F)<<4,
                                         (((*pixel_pos_c)<<2) & 0xA0) | (((*pixel_pos_c) & 0x00000003)<<4),
                                         ((*pixel_pos_c) & 0xA0) | (((*pixel_pos_c) & 0x00000003)<<4),
                                         (int) pre_conv_pos>>2,
                                         act_job->paper_colour_pattern,
                                         act_job->environment.dumper.printer_mode,
                                         act_job->black_mode_flag);
          }
        /* Update Catridge usage */
        pre_conv_usage_pattern|=*pre_conv_pos;
        pre_conv_pos++;
        }
      /* Move to next stripe line */
      line_pos+=line_size;
      }
    break;
    case 3: {
      /* Colour separation 8 bit per Colour */
      paper_colour_c=act_job->paper_colour_compare;
      full_black_c=act_job->full_black_compare;
      line_end_c=line_pos + line_length;
      for (pixel_pos_c=line_pos; pixel_pos_c < line_end_c; pixel_pos_c++) {
/* ??? Noch einbauen */
*pre_conv_pos=0x00000000;
        /* Update Catridge usage */
        pre_conv_usage_pattern|=*pre_conv_pos;
        pre_conv_pos++;
        }
      /* Move to next stripe line */
      line_pos+=line_size;
      }
    break;
    case 4: {
      /* Colour 16 bit */
      paper_colour_s=act_job->paper_colour_compare;
      full_black_s=act_job->full_black_compare;
      line_end_s=((unsigned short *) line_pos) + line_length;
      for (pixel_pos_s=(unsigned short *) line_pos; pixel_pos_s < line_end_s; pixel_pos_s++) {
        if ((*pixel_pos_s) == paper_colour_s) {
          *pre_conv_pos=act_job->paper_colour_pattern;
          }
        else if ((*pixel_pos_s) == full_black_s) {
          *pre_conv_pos=act_job->full_black_pattern;
          }
        else {
          *pre_conv_pos=find_best_colour(&act_job->colour_search,
                                         ((*pixel_pos_s) & 0x001F)<<3,
                                         ((*pixel_pos_s)>>2) & 0x00F1,
                                         ((*pixel_pos_s)>>7) & 0x00F1,
                                         (int) pre_conv_pos>>2,
                                         act_job->paper_colour_pattern,
                                         act_job->environment.dumper.printer_mode,
                                         act_job->black_mode_flag);
          }
        /* Update Catridge usage */
        pre_conv_usage_pattern|=*pre_conv_pos;
        pre_conv_pos++;
        }
      /* Move to next stripe line */
      line_pos+=line_size;
      }
    break;
    case 5: {
      /* Colour 32 bit */
      paper_colour_l=act_job->paper_colour_compare;
      full_black_l=act_job->full_black_compare;
      line_end_l=((unsigned long *) line_pos) + line_length;
      for (pixel_pos_l=(unsigned long *) line_pos; pixel_pos_l < line_end_l; pixel_pos_l++) {
        if ((*pixel_pos_l) == paper_colour_l) {
          *pre_conv_pos=act_job->paper_colour_pattern;
          }
        else if ((*pixel_pos_l) == full_black_l) {
          *pre_conv_pos=act_job->full_black_pattern;
          }
        else {
          *pre_conv_pos=find_best_colour(&act_job->colour_search,
                                         (*pixel_pos_l) & 0x000000FF,
                                         ((*pixel_pos_l)>>8) & 0x000000FF,
                                         ((*pixel_pos_l)>>16) & 0x000000FF,
                                         (int) pre_conv_pos>>2,
                                         act_job->paper_colour_pattern,
                                         act_job->environment.dumper.printer_mode,
                                         act_job->black_mode_flag);
          }
        /* Update Catridge usage */
        pre_conv_usage_pattern|=*pre_conv_pos;
        pre_conv_pos++;
        }
      /* Move to next stripe line */
      line_pos+=line_size;
      }
    break;
    }
  if ((act_job->environment.dumper.printer_mode == 0) ||
      (act_job->environment.dumper.printer_mode == 1)) {
    /* Now take data from preconverted line and put it into the accoring dumper buffers.
       Including separation of the colours. */
    pre_conv_end=act_job->preconverted_line + line_length;
    for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
      act_catridge_pixel_shift=act_catridge*act_job->environment.dumper.bits_per_printer_pixel;
      if ((pre_conv_usage_pattern & (pixel_mask<<act_catridge_pixel_shift)) != 0) {
/* {
  _kernel_swi_regs regs;

  sprintf(common.error_os.errmess, "passed cartridge %d \n", act_catridge);
  regs.r[0]=2;
  regs.r[1]=output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
} */
        /* Determine Group/Interlace and line of pixel data buffer */
        act_stage=0;
        act_strip_line=-1;
        while((act_strip_line < 0) &&
              (act_stage < act_job->environment.dumper.no_of_stages)) {
          act_v_interlace=0;
          while((act_strip_line < 0) &&
                (act_v_interlace < act_job->environment.printing_system.no_of_interlaces_vertical)) {
            h=act_job->act_page_line - *get_first_page_line_address(act_job,
                                                                    act_stage,
                                                                    act_v_interlace,
                                                                    0,
                                                                    act_catridge);
/* {
  _kernel_swi_regs regs;

  sprintf(common.error_os.errmess, "strip line %d %d %d %d %d %lx %d %lx\n", act_strip_line, act_stage, act_job->environment.dumper.no_of_stages, act_v_interlace, act_job->environment.printing_system.no_of_interlaces_vertical, act_job->act_page_line, h,
  *get_first_page_line_address(act_job,
                                                                    act_stage,
                                                                    act_v_interlace,
                                                                    0,
                                                                    act_catridge));
  regs.r[0]=2;
  regs.r[1]=output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
} */
            if ((h%act_job->environment.printing_system.no_of_interlaces_vertical) == 0) {
              if ((h >= 0) &&
                  (h < (act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head))) {
                act_strip_line=h/act_job->environment.printing_system.no_of_interlaces_vertical;
                }
              }
            if (act_strip_line < 0) act_v_interlace++;
            }
          if (act_strip_line < 0) act_stage++;
          }
        if (act_strip_line >= 0) {
          stripe_pos=get_stripe_address(act_job,
                                        act_stage,
                                        act_v_interlace,
                                        0,
                                        act_catridge,
                                        act_strip_line);
          /* Horizontal adjustment */
          h=8/act_job->environment.dumper.bits_per_printer_pixel;
          act_pos=act_job->colour_horizontal_adjustment[act_catridge]/h;
          h=(act_job->colour_horizontal_adjustment[act_catridge]%h)*act_job->environment.dumper.bits_per_printer_pixel;
          sub_pos=(8 - act_job->environment.dumper.bits_per_printer_pixel) - h;
          for (h=0; h < act_pos; h++) {
            *stripe_pos=0x00;
            stripe_pos++;
            }
          *stripe_pos=0x00;
          /* convert the preconverted line into according dumper buffer */
          for (pre_conv_pos=act_job->preconverted_line; pre_conv_pos < pre_conv_end; pre_conv_pos++) {
            *stripe_pos|=(((*pre_conv_pos)>>act_catridge_pixel_shift) & pixel_mask)<<sub_pos;
            if (sub_pos == 0) {
              /* Must be increased before the check */
              act_pos++;
              /* Optimize right blanks */
              if ((*stripe_pos != 0) &&
                  ((*get_max_stripe_usage_position_address(act_job,
                                                           act_stage,
                                                           act_v_interlace,
                                                           0,
                                                           act_catridge)) < act_pos)) {
                *get_max_stripe_usage_position_address(act_job,
                                                       act_stage,
                                                       act_v_interlace,
                                                       0,
                                                       act_catridge)=act_pos;
                }
              sub_pos=8 - act_job->environment.dumper.bits_per_printer_pixel;
              stripe_pos++;
              *stripe_pos=0x00;
              }
            else {
              sub_pos-=act_job->environment.dumper.bits_per_printer_pixel;
              }
            }
/* {
  _kernel_swi_regs regs;

  sprintf(common.error_os.errmess, "data in %d %d %d %d\n", act_stage, act_v_interlace, act_catridge, act_strip_line);
  regs.r[0]=2;
  regs.r[1]=output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
}  */
          *get_stripe_line_filled_address(act_job,
                                          act_stage,
                                          act_v_interlace,
                                          0,
                                          act_catridge,
                                          act_strip_line)=TRUE;
          }
        }
      }
    /* Update page line information and look whether a buffer must be flushed */
    act_job->act_page_line++;
    h=TRUE;
    act_stage=0;
    while (h &&
           (act_stage < act_job->environment.dumper.no_of_stages)) {
      act_v_interlace=0;
      while (h &&
             (act_v_interlace < act_job->environment.printing_system.no_of_interlaces_vertical)) {
        max_line_pos=-1000;
        for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
          if (max_line_pos < (*get_first_page_line_address(act_job,
                                                           act_stage,
                                                           act_v_interlace,
                                                           0,
                                                           act_catridge))) {
            max_line_pos=*get_first_page_line_address(act_job,
                                                      act_stage,
                                                      act_v_interlace,
                                                      0,
                                                      act_catridge);
            }
          }
        if (act_job->act_page_line >= (max_line_pos + (act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head))) {
          flush_data(act_job,
                     act_stage,
                     act_v_interlace,
                     output_file);
          h=FALSE;
          }
        act_v_interlace++;
        }
      act_stage++;
      }
    }
  else {
    write_sprite_line(&act_job->sprite_output,
                      output_file,
                      act_job->preconverted_line,
                      line_length,
                      act_job->paper_colour_pattern);
    act_job->act_page_line++;
    }
  act_job->colour_search.actual_line=(act_job->colour_search.actual_line + 1)%NUMBER_OF_DITHER_LINE_OFFSETS;
  }
return TRUE;
}

unsigned long translate_colour(unsigned long rgb_colour,
                               int stripe_type)
{

switch(stripe_type) {
  case 0: {
    /* Because only Back and White are used illuminance is calculated */
    if ((((rgb_colour>>8) & 0x000000FF) + ((rgb_colour>>16) & 0x000000FF) + ((rgb_colour>>24) & 0x000000FF)) >= 383) {
      return 1;
      }
    else {
      return 0;
      }
    }
  break;
  case 1: {
    /* Because Grey scales are used illuminance is calculated */
    return ((((rgb_colour>>8) & 0x000000FF) + ((rgb_colour>>16) & 0x000000FF) + ((rgb_colour>>24) & 0x000000FF)))/3;
    }
  break;
  case 2: {
    unsigned long colour_illuminance;
    unsigned long target_colour;

    /* Maximum of Darkness is 3*63=189.
       This is retrived from the darkness of the remaining 6 Bits of each colour.
       This is divided into 4 ranges and the range number is stored
       inside the two Black bits and translated afterwards into
       dithering. */
    colour_illuminance=((rgb_colour>>8) & 0x0000003F)+((rgb_colour>>16) & 0x0000003F)+((rgb_colour>>24) & 0x0000003F);
    if (colour_illuminance <= 47) {
      target_colour=0;
      }
    else if (colour_illuminance <= 95) {
      target_colour=1;
      }
    else if (colour_illuminance <= 143) {
      target_colour=2;
      }
    else {
      target_colour=3;
      }
    /* Red, Green and Blue are having a value range of 0-255
       2 Bit at Top are taken as value */
    target_colour|=((rgb_colour>>14) & 0x00000003)<<2;
    target_colour|=((rgb_colour>>22) & 0x00000003)<<4;
    return target_colour | (((rgb_colour>>30) & 0x00000003)<<6);
    }
  break;
  case 4: {
    /* pack to format */
    return ((rgb_colour>>11) & 0x0000001F) | ((rgb_colour>>11) & 0x000003E0) | ((rgb_colour>>11) & 0x00007C00);
    }
  break;
  case 5: {
    /* pack to format */
    return rgb_colour>>8;
    }
  break;
  default: {
    return 0;
    }
  }
}

int start_page(struct job_struct *act_job,
               int output_file,
               int blank_left_pixels,
               int blank_pixel_lines,
               int horizontal_resolution,
               int vertical_resolution,
               int *remaining_copies,
               int stripe_type)
{
int i;
int h;
int act_stage;
int act_v_interlace;
int act_catridge;
int max_line_pos;
_kernel_swi_regs regs;

if (!act_job) {
  return -1;
  }
#ifdef DEBUG_MODE
if ((act_job->magic1!=23456) ||
    (act_job->magic2!=78901)) {
  _kernel_swi_regs regs;

  sprintf(common.error_os.errmess, "job violation page start %d %d", act_job->magic1, act_job->magic2);
  regs.r[0]=2;
  regs.r[1]=output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return -1;
  }
act_job->output_file=output_file;
#endif
/* Set up the environment */
act_job->environment.printing_system.line_offset_horizontal=blank_left_pixels;
act_job->environment.printing_system.page_offset_vertical=blank_pixel_lines;
act_job->environment.dumper.remaining_page_offset_vertical=blank_pixel_lines;
act_job->environment.printing_system.resolution_horizontal=horizontal_resolution;
act_job->environment.printing_system.resolution_vertical=vertical_resolution;
act_job->environment.job_state.remaining_copies=*remaining_copies;
act_job->environment.dumper.remaining_copies=*remaining_copies;
/* All values in millipoints which is 1/72000 of an inch.
   Unit of variable is 1/10000 inch */
_kernel_swi(PDriver_PageSize, &regs, &regs);
act_job->environment.printing_system.page_width=(regs.r[1]*10)/72;
act_job->environment.printing_system.page_height=(regs.r[2]*10)/72;
act_job->environment.printing_system.page_range_top_left_horizontal=(regs.r[3]*10)/72;
act_job->environment.printing_system.page_range_top_left_vertical=((regs.r[2]-regs.r[6])*10)/72;
act_job->environment.printing_system.page_range_bottom_right_horizontal=(regs.r[5]*10)/72;
act_job->environment.printing_system.page_range_bottom_right_vertical=((regs.r[2]-regs.r[4])*10)/72;
/* Claim page space */
/* First calculate maximal number of pixels per line */
act_job->maximal_preconv_width=(act_job->environment.printing_system.page_width*act_job->environment.printing_system.resolution_horizontal)/10000;
act_job->maximal_bytes_per_line_storage=/* Security pixel offset */
                                        32 +
                                        act_job->maximal_preconv_width;
if ((act_job->preconverted_line=dumper_malloc(act_job->dynamic_area,
                                              sizeof(unsigned long)*
                                              act_job->maximal_bytes_per_line_storage)) == NULL) {
  return -2;
  }
/* Each pixel is represented as a certain amount of bits per colour but not more
   then 8 bit. For each of this pixels storage must be reserved */
act_job->maximal_bytes_per_line_storage=(act_job->maximal_bytes_per_line_storage*act_job->environment.dumper.bits_per_printer_pixel)/8;
if ((act_job->environment.dumper.printer_mode == 0) ||
    (act_job->environment.dumper.printer_mode == 1)) {
  if ((act_job->stripe=dumper_malloc(act_job->dynamic_area,
                                     sizeof(unsigned char)*
                                     act_job->environment.dumper.no_of_stages*
                                     act_job->environment.printing_system.no_of_interlaces_vertical*
                                     act_job->environment.printing_system.no_of_interlaces_horizontal*
                                     act_job->environment.dumper.no_of_printer_catridges*
                                     act_job->environment.printing_system.dots_of_print_head*
                                     act_job->maximal_bytes_per_line_storage)) == NULL) {
    dumper_free(act_job->dynamic_area,
                act_job->preconverted_line);
    act_job->preconverted_line=NULL;
    return -2;
    }
  if ((act_job->compressed_stripe=dumper_malloc(act_job->dynamic_area,
                                                sizeof(unsigned char)*
                                                act_job->environment.printing_system.dots_of_print_head*
                                                (act_job->maximal_bytes_per_line_storage +
                                                /* Can be larger then orignal in worst case. */
                                                WORST_CASE_COMPRESSION_OFFSET))) == NULL) {
    dumper_free(act_job->dynamic_area,
                act_job->stripe);
    act_job->stripe=NULL;
    dumper_free(act_job->dynamic_area,
                act_job->preconverted_line);
    act_job->preconverted_line=NULL;
    return -2;
    }
  if ((act_job->compressed_stripe_size=dumper_malloc(act_job->dynamic_area,
                                                     sizeof(unsigned long)*
                                                     act_job->environment.printing_system.dots_of_print_head)) == NULL) {
    dumper_free(act_job->dynamic_area,
                act_job->compressed_stripe);
    act_job->compressed_stripe=NULL;
    dumper_free(act_job->dynamic_area,
                act_job->stripe);
    act_job->stripe=NULL;
    dumper_free(act_job->dynamic_area,
                act_job->preconverted_line);
    act_job->preconverted_line=NULL;
    return -2;
    }
  /* Start Printer output */
  sent_control_string(&act_job->page_start,
                      output_file,
                      &act_job->environment);
  /* Calibration might have been changed */
  if (act_job->loaded_calibration != act_job->environment.dumper.calibration) {
    FILE *settings_file;
    int file_section;
    char actual_data_line[512];

    if ((settings_file=fopen(act_job->environment.settings_file_name, "r")) != NULL) {
      drop_search_range(&act_job->colour_search);
      act_job->paper_colour_compare=0xFFFFFFFF;
      act_job->paper_colour_pattern=0;
      act_job->full_black_compare=0xFFFFFFFF;
      act_job->full_black_pattern=0;
      act_job->black_mode_flag=FALSE;
      file_section=FILE_SECTION_INDETERMINED;
      actual_data_line[511]='\0';
      while(!feof(settings_file)) {
        if (fgets(actual_data_line,
                  511,
                  settings_file)) {
          /* Ignore comments */
          if (strncmp(actual_data_line,
                      FILE_COMMENT,
                      strlen(FILE_COMMENT)) != 0) {
            if (strncmp(actual_data_line,
                        FILE_COLOUR_CALIBRATION_START,
                        strlen(FILE_COLOUR_CALIBRATION_START)) == 0) {
              long actual_calibration;

              /* Determine number of calibration */
              actual_calibration=atol(&actual_data_line[strlen(FILE_COLOUR_CALIBRATION_START)]);
              /* Check whether calibration is required calibration */
              if (actual_calibration == act_job->environment.dumper.calibration) {
                file_section=FILE_SECTION_COLOUR_CALIBRATION;
                act_job->loaded_calibration=act_job->environment.dumper.calibration;
                }
              else {
                file_section=FILE_SECTION_INDETERMINED;
                }
              }
            else if (strncmp(actual_data_line,
                             FILE_COLOUR_CALIBRATION_END,
                             strlen(FILE_COLOUR_CALIBRATION_END)) == 0) {
              file_section=FILE_SECTION_INDETERMINED;
              }
            else {
              switch(file_section) {
                case FILE_SECTION_COLOUR_CALIBRATION: {
                  struct searchable_range colour_search_entry;

                  /* Default for optional elements */
                  colour_search_entry.paper_colour_fraction=0;
                  if (sscanf(actual_data_line,
                             "%ld %ld %ld %ld %ld %ld %ld %ld %ld %lx %lx %ld",
                             &colour_search_entry.colour[0],
                             &colour_search_entry.colour[1],
                             &colour_search_entry.colour[2],
                             &colour_search_entry.span[0][0],
                             &colour_search_entry.span[0][1],
                             &colour_search_entry.span[1][0],
                             &colour_search_entry.span[1][1],
                             &colour_search_entry.span[2][0],
                             &colour_search_entry.span[2][1],
                             &colour_search_entry.colour_mapping,
                             &colour_search_entry.group_mask,
                             /* optional */
                             &colour_search_entry.paper_colour_fraction) >= 11) {
                    insert_search_range(&colour_search_entry,
                                        &act_job->colour_search);
                    /* Check for Black mode */
                    if ((colour_search_entry.group_mask & COLOUR_GROUP_BLACK_GROUP) != 0) {
                      act_job->black_mode_flag=TRUE;
                      }
                    /* Store special colours for speed up purposes */
                    if ((colour_search_entry.group_mask & COLOUR_GROUP_PAPER_COLOUR) != 0) {
                      act_job->paper_colour=colour_search_entry.colour[0] | (colour_search_entry.colour[1]<<8) | (colour_search_entry.colour[2]<<16);
                      act_job->paper_colour_compare=translate_colour(act_job->paper_colour<<8,
                                                                     stripe_type);
                      act_job->paper_colour_pattern=colour_search_entry.colour_mapping;
                      }
                    else if ((colour_search_entry.group_mask & COLOUR_GROUP_PURE_BLACK) != 0) {
                      act_job->full_black=colour_search_entry.colour[0] | (colour_search_entry.colour[1]<<8) | (colour_search_entry.colour[2]<<16);
                      act_job->full_black_compare=translate_colour(act_job->full_black<<8,
                                                                   stripe_type);
                      act_job->full_black_pattern=colour_search_entry.colour_mapping;
                      }
                    }
                  }
                break;
                }
              }
            }
          }
        }
      fclose(settings_file);
      }
    }
  }
if ((act_job->environment.dumper.printer_mode == 2) ||
    (act_job->environment.dumper.printer_mode == 3)) {
  /* Start Printer output */
  initialize_sprite_page(&act_job->sprite_output,
                         output_file,
                         /* Same as above for preconverted line because
                            the preconverted line is the base. */
                         act_job->maximal_preconv_width,
                         FALSE);
  }
else if (act_job->environment.dumper.printer_mode == 4) {
  /* Start Printer output */
  initialize_sprite_page(&act_job->sprite_output,
                         output_file,
                         /* Same as above for preconverted line because
                            the preconverted line is the base. */
                         act_job->maximal_preconv_width,
                         TRUE);
  }
act_job->act_page_line=(act_job->environment.dumper.no_of_stages/2)*act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head;
if ((act_job->environment.dumper.printer_mode == 0) ||
    (act_job->environment.dumper.printer_mode == 1)) {
  /* Initialize the buffers */
  for (act_stage=0; act_stage < act_job->environment.dumper.no_of_stages; act_stage++) {
    for (act_v_interlace=0; act_v_interlace < act_job->environment.printing_system.no_of_interlaces_vertical; act_v_interlace++) {
      for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
        *get_max_stripe_usage_position_address(act_job,
                                               act_stage,
                                               act_v_interlace,
                                               0,
                                               act_catridge)=0;
        for (i=0; i < act_job->environment.printing_system.dots_of_print_head; i++) *get_stripe_line_filled_address(act_job,
                                                                                                                    act_stage,
                                                                                                                    act_v_interlace,
                                                                                                                    0,
                                                                                                                    act_catridge,
                                                                                                                    i)=FALSE;
        /* Determine the first line page of each storage at start of a page. */
        /* Each stages represents dots of print head multiplied by number
           of interlaces lines */
        h=act_stage*act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head;
/* {
    _kernel_swi_regs regs;

          sprintf(common.error_os.errmess, "a %d = %d * %d * %d\n", h, act_stage, act_job->environment.printing_system.no_of_interlaces_vertical, act_job->environment.printing_system.dots_of_print_head);
          regs.r[0]=2;
          regs.r[1]=output_file;
          regs.r[2]=(int) common.error_os.errmess;
          regs.r[3]=strlen(common.error_os.errmess);
          _kernel_swi(OS_GBPB, &regs, &regs);
  } */
        /* Offset by interlace */
        h+=act_v_interlace*act_job->environment.printing_system.dots_of_print_head + act_v_interlace;
/* {
    _kernel_swi_regs regs;

          sprintf(common.error_os.errmess, "b %d += %d * %d + %d\n", h, act_v_interlace, act_job->environment.printing_system.dots_of_print_head, act_v_interlace);
          regs.r[0]=2;
          regs.r[1]=output_file;
          regs.r[2]=(int) common.error_os.errmess;
          regs.r[3]=strlen(common.error_os.errmess);
          _kernel_swi(OS_GBPB, &regs, &regs);
  } */
        /* Offset by catridge group relation and local adjustment */
        h+=act_job->catridge_position[act_catridge]*act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head + act_job->colour_vertical_adjustment[act_catridge];
/*{
    _kernel_swi_regs regs;

          sprintf(common.error_os.errmess, "c %d += %d * %d * %d + %d\n", h, act_job->catridge_position[act_catridge], act_job->environment.printing_system.no_of_interlaces_vertical, act_job->environment.printing_system.dots_of_print_head, act_job->colour_vertical_adjustment[act_catridge]);
          regs.r[0]=2;
          regs.r[1]=output_file;
          regs.r[2]=(int) common.error_os.errmess;
          regs.r[3]=strlen(common.error_os.errmess);
          _kernel_swi(OS_GBPB, &regs, &regs);
          sprintf(common.error_os.errmess, "Stage %d v_i %d catr %d at %d Pos %d\n", act_stage, act_v_interlace, act_catridge, h, act_job->catridge_position[act_catridge]);
          regs.r[0]=2;
          regs.r[1]=output_file;
          regs.r[2]=(int) common.error_os.errmess;
          regs.r[3]=strlen(common.error_os.errmess);
          _kernel_swi(OS_GBPB, &regs, &regs);
  } */
        *get_first_page_line_address(act_job,
                                     act_stage,
                                     act_v_interlace,
                                     0,
                                     act_catridge)=h;
        }
      }
    }
  /* Necassary correction of start position */
  /* ??? Kommentar ergnzen */
  for (act_stage=0; act_stage < act_job->environment.dumper.no_of_stages; act_stage++) {
    for (act_v_interlace=0; act_v_interlace < act_job->environment.printing_system.no_of_interlaces_vertical; act_v_interlace++) {
      max_line_pos=-1000;
      for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
        if (max_line_pos < (*get_first_page_line_address(act_job,
                                                         act_stage,
                                                         act_v_interlace,
                                                         0,
                                                         act_catridge))) {
          max_line_pos=*get_first_page_line_address(act_job,
                                                    act_stage,
                                                    act_v_interlace,
                                                    0,
                                                    act_catridge);
          }
        }
      if (act_job->act_page_line >= (max_line_pos + (act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head))) {
        for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
          *get_first_page_line_address(act_job,
                                       act_stage,
                                       act_v_interlace,
                                       0,
                                       act_catridge)=*get_first_page_line_address(act_job,
                                                                                  act_stage,
                                                                                  act_v_interlace,
                                                                                  0,
                                                                                  act_catridge) +
                                                     act_job->environment.dumper.no_of_stages*act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head;
          }
        }
      }
    }
/* {
  _kernel_swi_regs regs;

  for (act_stage=0; act_stage < act_job->environment.dumper.no_of_stages; act_stage++) {
    for (act_v_interlace=0; act_v_interlace < act_job->environment.printing_system.no_of_interlaces_vertical; act_v_interlace++) {
      for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
        sprintf(common.error_os.errmess, "Start Stage %d v_i %d catr %d at %d\n", act_stage, act_v_interlace, act_catridge, *get_first_page_line_address(act_job,
                                     act_stage,
                                     act_v_interlace,
                                     0,
                                     act_catridge));
        regs.r[0]=2;
        regs.r[1]=output_file;
        regs.r[2]=(int) common.error_os.errmess;
        regs.r[3]=strlen(common.error_os.errmess);
        _kernel_swi(OS_GBPB, &regs, &regs);
        }
      }
    }
} */
  }
*remaining_copies=act_job->environment.dumper.remaining_copies;
/* Either PDF corrects number of copies or not.
   If it doesn't correct the value last copy is 1 which stays unchanged else value should be set to 0 after
   all pages have been processed. After last copy has been printed increase number of page by one. */
if (((act_job->environment.job_state.remaining_copies == act_job->environment.dumper.remaining_copies) &&
     (act_job->environment.dumper.remaining_copies == 1)) ||
    (act_job->environment.dumper.remaining_copies == 0)) {
  act_job->environment.job_state.act_page++;
  }
return act_job->environment.dumper.remaining_page_offset_vertical;
}

int end_page(struct job_struct *act_job,
             int output_file)
{
int i, h;
int act_stage;
int act_v_interlace;
int act_catridge;
unsigned long max_line_pos;

if (!act_job) {
  return FALSE;
  }
#ifdef DEBUG_MODE
if ((act_job->magic1!=23456) ||
    (act_job->magic2!=78901)) {
  _kernel_swi_regs regs;

  sprintf(common.error_os.errmess, "job violation page stop %d %d", act_job->magic1, act_job->magic2);
  regs.r[0]=2;
  regs.r[1]=output_file;
  regs.r[2]=(int) common.error_os.errmess;
  regs.r[3]=strlen(common.error_os.errmess);
  _kernel_swi(OS_GBPB, &regs, &regs);
  return FALSE;
  }
#endif
if ((act_job->environment.dumper.printer_mode == 0) ||
    (act_job->environment.dumper.printer_mode == 1)) {
  /* Flush remaining lines.
     Must be (STAGES*VERTICAL_INTERLACES*ROW_HIGH)-1 to flush every part */
  for (i=0; i < ((act_job->environment.dumper.no_of_stages*act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head) - 1); i++) {
    act_job->act_page_line++;
    h=TRUE;
    act_stage=0;
    while (h &&
           (act_stage < act_job->environment.dumper.no_of_stages)) {
      act_v_interlace=0;
      while (h &&
             (act_v_interlace < act_job->environment.printing_system.no_of_interlaces_vertical)) {
        max_line_pos=0;
        for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
          if (max_line_pos < (*get_first_page_line_address(act_job,
                                                          act_stage,
                                                          act_v_interlace,
                                                          0,
                                                          act_catridge))) {
            max_line_pos=*get_first_page_line_address(act_job,
                                                      act_stage,
                                                      act_v_interlace,
                                                      0,
                                                      act_catridge);
            }
          }
        if (act_job->act_page_line >= (max_line_pos + (act_job->environment.printing_system.no_of_interlaces_vertical*act_job->environment.printing_system.dots_of_print_head))) {
          flush_data(act_job,
                     act_stage,
                     act_v_interlace,
                     output_file);
          h=FALSE;
          }
        act_v_interlace++;
        }
      act_stage++;
      }
    }
  sent_control_string(&act_job->page_end,
                      output_file,
                      &act_job->environment);
  }
else if ((act_job->environment.dumper.printer_mode == 2) ||
         (act_job->environment.dumper.printer_mode == 3) ||
         (act_job->environment.dumper.printer_mode == 4)) {
  finish_sprite_page(&act_job->sprite_output,
                     output_file);
  }
return TRUE;
}

struct job_struct *start_job(int stripe_type,
                             int *error_code,
                             int output_file)
{
int act_catridge;
int i;
int dynamic_area;
struct job_struct *act_job;
_kernel_swi_regs regs;
FILE *settings_file;

/* No need for PDumperSupport modul */
dynamic_area=dumper_dynamic_area_initialize(20000000);
if ((act_job=dumper_malloc(dynamic_area,
                           sizeof(struct job_struct))) == NULL) return NULL;
#ifdef DEBUG_MODE
act_job->magic1=23456;
act_job->magic2=78901;
#endif
act_job->dynamic_area=dynamic_area;
act_job->preconverted_line=NULL;
act_job->stripe=NULL;
act_job->compressed_stripe=NULL;
act_job->compressed_stripe_size=NULL;
initalize_stack(&act_job->environment,
                output_file,
                common.stack_trace_flag);
*error_code=-1;
initialize_search_range(&act_job->colour_search,
                        act_job->dynamic_area,
                        common.dither_line_offset,
                        output_file);
/* Set default for printer specific settings */
act_job->loaded_calibration=-1;
act_job->paper_colour_compare=0xFFFFFFFF;
act_job->paper_colour_pattern=0;
act_job->full_black_compare=0xFFFFFFFF;
act_job->full_black_pattern=0;
act_job->black_mode_flag=FALSE;
for (act_catridge=0; act_catridge < MAX_CATRIDGES; act_catridge++) {
  act_job->colour_vertical_adjustment[act_catridge]=0;
  act_job->colour_horizontal_adjustment[act_catridge]=0;
  }
/* Some printer specific properties are located inside
   a special printer dumper string (zero skip) as bytes:
   Byte 0  - Bits per printer pixel (Default 2)
   Byte 1  - Printer mode (Default 0)
   Byte 2  - Headposition of catridge 1 (Default 0)
     ...
   Byte 11 - Headposition of catridge 10 (Default 0)
   Byte 12 - Data compression mode
   Byte 13 - Default calibration */
if (common.printer_properties.length >= 1) {
  act_job->environment.dumper.bits_per_printer_pixel=common.printer_properties.sequence[0];
  }
else {
  act_job->environment.dumper.bits_per_printer_pixel=2;
  }
if (common.printer_properties.length >= 2) {
  act_job->environment.dumper.printer_mode=common.printer_properties.sequence[1];
  }
else {
  act_job->environment.dumper.printer_mode=0;
  }
for (act_catridge=0; act_catridge < MAX_CATRIDGES; act_catridge++) {
  if (common.printer_properties.length >= (act_catridge + 3)) {
    act_job->catridge_position[act_catridge]=common.printer_properties.sequence[act_catridge + 2];
    }
  else {
    act_job->catridge_position[act_catridge]=0;
    }
  }
if (common.printer_properties.length >= 13) {
  act_job->environment.dumper.compression_format=common.printer_properties.sequence[12];
  }
else {
  act_job->environment.dumper.compression_format=0;
  }
if (common.printer_properties.length >= 14) {
  act_job->environment.dumper.calibration=common.printer_properties.sequence[13];
  }
else {
  act_job->environment.dumper.calibration=0;
  }
/* Prepare pallette information */
if (act_job->environment.dumper.printer_mode == 4) {
  initialize_sprite_pallette(&act_job->sprite_output);
  }
/* Evaluate Printer specific settings */
_kernel_swi(PDriver_Info, &regs, &regs);
sprintf(act_job->environment.settings_file_name,
        "<Printers$Dir>.Resources.PDumpers.PDumperEI.%s",
        (char *) regs.r[4]);
if ((settings_file=fopen(act_job->environment.settings_file_name, "r")) == NULL) {
  *error_code=-2;
  drop_search_range(&act_job->colour_search);
  dynamic_area=act_job->dynamic_area;
  dumper_free(act_job->dynamic_area,
              act_job);
  dumper_dynamic_area_release(dynamic_area);
  return NULL;
  }
else {
  int file_section;
  char actual_data_line[512];

  file_section=FILE_SECTION_INDETERMINED;
  actual_data_line[511]='\0';
  while(!feof(settings_file)) {
    if (fgets(actual_data_line,
              511,
              settings_file)) {
      /* Ignore comments */
      if (strncmp(actual_data_line,
                  FILE_COMMENT,
                  strlen(FILE_COMMENT)) != 0) {
        if (strncmp(actual_data_line,
                    FILE_HEAD_ADJUSTMENT_START,
                    strlen(FILE_HEAD_ADJUSTMENT_START)) == 0) {
          file_section=FILE_SECTION_HEAD_ADJUSTMENT;
          }
        else if (strncmp(actual_data_line,
                         FILE_HEAD_ADJUSTMENT_END,
                         strlen(FILE_HEAD_ADJUSTMENT_END)) == 0) {
          file_section=FILE_SECTION_INDETERMINED;
          }
        else if (strncmp(actual_data_line,
                         FILE_COLOUR_CALIBRATION_START,
                         strlen(FILE_COLOUR_CALIBRATION_START)) == 0) {
          long actual_calibration;

          /* Determine number of calibration */
          actual_calibration=atol(&actual_data_line[strlen(FILE_COLOUR_CALIBRATION_START)]);
          /* Check whether calibration is required calibration */
          if (actual_calibration == act_job->environment.dumper.calibration) {
            file_section=FILE_SECTION_COLOUR_CALIBRATION;
            act_job->loaded_calibration=act_job->environment.dumper.calibration;
            }
          else {
            file_section=FILE_SECTION_INDETERMINED;
            }
          }
        else if (strncmp(actual_data_line,
                         FILE_COLOUR_CALIBRATION_END,
                         strlen(FILE_COLOUR_CALIBRATION_END)) == 0) {
          file_section=FILE_SECTION_INDETERMINED;
          }
        else {
          switch(file_section) {
            case FILE_SECTION_HEAD_ADJUSTMENT: {
              char c;

              if (sscanf(actual_data_line,
                         "%1s %d %d",
                         &c,
                         &act_catridge,
                         &i) == 3) {
                if ((act_catridge >= 0) &&
                    (act_catridge < MAX_CATRIDGES)) {
                  if (c == 'v') {
                    act_job->colour_vertical_adjustment[act_catridge]=i;
                    }
                  else if (c == 'h') {
                    if (i >=0 ) {
                      act_job->colour_horizontal_adjustment[act_catridge]=i;
                      }
                    }
                  }
                }
              }
            break;
            case FILE_SECTION_COLOUR_CALIBRATION: {
              struct searchable_range colour_search_entry;

              /* Default for optional elements */
              colour_search_entry.paper_colour_fraction=0;
              if (sscanf(actual_data_line,
                         "%ld %ld %ld %ld %ld %ld %ld %ld %ld %lx %lx %ld",
                         &colour_search_entry.colour[0],
                         &colour_search_entry.colour[1],
                         &colour_search_entry.colour[2],
                         &colour_search_entry.span[0][0],
                         &colour_search_entry.span[0][1],
                         &colour_search_entry.span[1][0],
                         &colour_search_entry.span[1][1],
                         &colour_search_entry.span[2][0],
                         &colour_search_entry.span[2][1],
                         &colour_search_entry.colour_mapping,
                         &colour_search_entry.group_mask,
                         /* optional */
                         &colour_search_entry.paper_colour_fraction) >= 11) {
                if (act_job->environment.dumper.printer_mode != 2) {
                  insert_search_range(&colour_search_entry,
                                      &act_job->colour_search);
                  }
                /* Build pallette information at mode 4 */
                if (act_job->environment.dumper.printer_mode == 4) {
                  if (!register_sprite_pallette_entry(&act_job->sprite_output,
                                                      colour_search_entry.colour_mapping,
                                                      colour_search_entry.colour[0] | (colour_search_entry.colour[1]<<8) | (colour_search_entry.colour[2]<<16))) {
                    /* Fallback at palette sprite generation */
                    act_job->environment.dumper.printer_mode=3;
                    }
                  }
                /* Check for Black mode */
                if ((colour_search_entry.group_mask & COLOUR_GROUP_BLACK_GROUP) != 0) {
                  act_job->black_mode_flag=TRUE;
                  }
                /* Store special colours for speed up purposes */
                if ((colour_search_entry.group_mask & COLOUR_GROUP_PAPER_COLOUR) != 0) {
                  act_job->paper_colour=colour_search_entry.colour[0] | (colour_search_entry.colour[1]<<8) | (colour_search_entry.colour[2]<<16);
                  act_job->paper_colour_compare=translate_colour(act_job->paper_colour<<8,
                                                                 stripe_type);
                  act_job->paper_colour_pattern=colour_search_entry.colour_mapping;
                  }
                else if ((colour_search_entry.group_mask & COLOUR_GROUP_PURE_BLACK) != 0) {
                  act_job->full_black=colour_search_entry.colour[0] | (colour_search_entry.colour[1]<<8) | (colour_search_entry.colour[2]<<16);
                  act_job->full_black_compare=translate_colour(act_job->full_black<<8,
                                                               stripe_type);
                  act_job->full_black_pattern=colour_search_entry.colour_mapping;
                  }
                }
              }
            break;
            }
          }
        }
      }
    }
  fclose(settings_file);
  }
/* Check whether required calibration has been found */
if (act_job->loaded_calibration == -1) {
  *error_code=-3;
  drop_search_range(&act_job->colour_search);
  dynamic_area=act_job->dynamic_area;
  dumper_free(act_job->dynamic_area,
              act_job);
  dumper_dynamic_area_release(dynamic_area);
  return NULL;
  }
/* Set up the environment */
act_job->environment.job_state.job_number=common.job_number;
common.job_number++;
act_job->environment.job_state.act_page=1;
act_job->environment.printing_system.no_of_interlaces_vertical=common.no_of_interlaces_vertical;
act_job->environment.printing_system.no_of_interlaces_horizontal=common.no_of_interlaces_horizontal;
act_job->environment.printing_system.dots_of_print_head=common.dots_of_print_head;
act_job->environment.dumper.no_of_stages=common.no_of_stages;
act_job->environment.dumper.no_of_printer_catridges=0;
if ((act_job->environment.dumper.printer_mode == 0) ||
    (act_job->environment.dumper.printer_mode == 1)) {
  /* Determine number of catridges by used colour control sequences */
  while ((act_job->environment.dumper.no_of_printer_catridges < MAX_CATRIDGES) &&
         (common.line_pass[act_job->environment.dumper.no_of_printer_catridges].length > 0)) {
    act_job->environment.dumper.no_of_printer_catridges++;
    }
  /* Exception for Page size mode because there are no cartridge sequences given in that case */
  if ((act_job->environment.dumper.no_of_printer_catridges == 0) &&
      (act_job->environment.dumper.printer_mode == 1)) {
    act_job->environment.dumper.no_of_printer_catridges=1;
    }
  }
if ((act_job->environment.dumper.printer_mode == 2) ||
    (act_job->environment.dumper.printer_mode == 3)) {
  /* Necessary to force special colours properly set at
     certain sprite modes. Not needed at palette sprites
     because colour translation must be performed in
     such cases. */
  act_job->paper_colour_pattern=act_job->paper_colour;
  act_job->full_black_pattern=act_job->full_black;
  }
if ((act_job->environment.dumper.printer_mode == 2) ||
    (act_job->environment.dumper.printer_mode == 3) ||
    (act_job->environment.dumper.printer_mode == 4)) {
  initialize_sprite_output(&act_job->sprite_output);
  }
/* Allocate according space */
if ((act_job->environment.dumper.printer_mode == 0) ||
    (act_job->environment.dumper.printer_mode == 1)) {
  if ((act_job->line_pass=dumper_malloc(act_job->dynamic_area,
                                        sizeof(struct command_sequence_struct)*act_job->environment.dumper.no_of_printer_catridges)) == NULL) {
    drop_search_range(&act_job->colour_search);
    dynamic_area=act_job->dynamic_area;
    dumper_free(act_job->dynamic_area,
                act_job);
    dumper_dynamic_area_release(dynamic_area);
    return NULL;
    }
  if ((act_job->line_end=dumper_malloc(act_job->dynamic_area,
                                       sizeof(struct command_sequence_struct)*act_job->environment.printing_system.no_of_interlaces_vertical)) == NULL) {
    if (act_job->line_pass) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_pass);
      }
    drop_search_range(&act_job->colour_search);
    dynamic_area=act_job->dynamic_area;
    dumper_free(act_job->dynamic_area,
                act_job);
    dumper_dynamic_area_release(dynamic_area);
    return NULL;
    }
  if ((act_job->first_page_line=dumper_malloc(act_job->dynamic_area,
                                              sizeof(int)*
                                              act_job->environment.dumper.no_of_stages*
                                              act_job->environment.printing_system.no_of_interlaces_vertical*
                                              act_job->environment.printing_system.no_of_interlaces_horizontal*
                                              act_job->environment.dumper.no_of_printer_catridges)) == NULL) {
    if (act_job->line_end) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_end);
      }
    if (act_job->line_pass) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_pass);
      }
    drop_search_range(&act_job->colour_search);
    dynamic_area=act_job->dynamic_area;
    dumper_free(act_job->dynamic_area,
                act_job);
    dumper_dynamic_area_release(dynamic_area);
    return NULL;
    }
  if ((act_job->max_stripe_usage_position=dumper_malloc(act_job->dynamic_area,
                                                        sizeof(unsigned long)*
                                                        act_job->environment.dumper.no_of_stages*
                                                        act_job->environment.printing_system.no_of_interlaces_vertical*
                                                        act_job->environment.printing_system.no_of_interlaces_horizontal*
                                                        act_job->environment.dumper.no_of_printer_catridges)) == NULL) {
    if (act_job->first_page_line) {
      dumper_free(act_job->dynamic_area,
                  act_job->first_page_line);
      }
    if (act_job->line_end) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_end);
      }
    if (act_job->line_pass) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_pass);
      }
    drop_search_range(&act_job->colour_search);
    dynamic_area=act_job->dynamic_area;
    dumper_free(act_job->dynamic_area,
                act_job);
    dumper_dynamic_area_release(dynamic_area);
    return NULL;
    }
  if ((act_job->stripe_line_filled=dumper_malloc(act_job->dynamic_area,
                                                 sizeof(unsigned char)*
                                                 act_job->environment.dumper.no_of_stages*
                                                 act_job->environment.printing_system.no_of_interlaces_vertical*
                                                 act_job->environment.printing_system.no_of_interlaces_horizontal*
                                                 act_job->environment.dumper.no_of_printer_catridges*
                                                 act_job->environment.printing_system.dots_of_print_head)) == NULL) {
    if (act_job->max_stripe_usage_position) {
      dumper_free(act_job->dynamic_area,
                  act_job->max_stripe_usage_position);
      }
    if (act_job->first_page_line) {
      dumper_free(act_job->dynamic_area,
      act_job->first_page_line);
      }
    if (act_job->line_end) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_end);
      }
    if (act_job->line_pass) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_pass);
      }
    drop_search_range(&act_job->colour_search);
    dynamic_area=act_job->dynamic_area;
    dumper_free(act_job->dynamic_area,
                act_job);
    dumper_dynamic_area_release(dynamic_area);
    return NULL;
    }
  /* Copy actual dumper sequences into local ones */
  copy_control_string(&act_job->page_start,
                      &common.page_start);
  copy_control_string(&act_job->page_end,
                      &common.page_end);
  for (act_catridge=0; act_catridge < act_job->environment.dumper.no_of_printer_catridges; act_catridge++) {
    copy_control_string(&act_job->line_pass[act_catridge],
                        &common.line_pass[act_catridge]);
    }
  for (i=0; i < act_job->environment.printing_system.no_of_interlaces_vertical; i++) {
    copy_control_string(&act_job->line_end[i],
                        &common.line_end[i]);
    }
  }
else {
  act_job->line_pass=NULL;
  act_job->line_end=NULL;
  act_job->first_page_line=NULL;
  act_job->max_stripe_usage_position=NULL;
  act_job->stripe_line_filled=NULL;
  }
/* Copy actual dumper sequences valid for all modes
   into local ones */
copy_control_string(&act_job->line_return,
                    &common.line_return);
return act_job;
}

int abort_job(struct job_struct *act_job,
              int reason_code)
{
int dynamic_area;

if (reason_code == 0) {
  if (act_job) {
    if (act_job->compressed_stripe_size) {
      dumper_free(act_job->dynamic_area,
                  act_job->compressed_stripe_size);
      act_job->compressed_stripe_size=NULL;
      }
    if (act_job->compressed_stripe) {
      dumper_free(act_job->dynamic_area,
                  act_job->compressed_stripe);
      act_job->compressed_stripe=NULL;
      }
    if (act_job->stripe) {
      dumper_free(act_job->dynamic_area,
                  act_job->stripe);
      act_job->stripe=NULL;
      }
    if (act_job->preconverted_line) {
      dumper_free(act_job->dynamic_area,
                  act_job->preconverted_line);
      act_job->preconverted_line=NULL;
      }
    }
  }
else {
  if (act_job) {
    if (act_job->compressed_stripe_size) {
      dumper_free(act_job->dynamic_area,
                  act_job->compressed_stripe_size);
      act_job->compressed_stripe_size=NULL;
      }
    if (act_job->compressed_stripe) {
      dumper_free(act_job->dynamic_area,
                  act_job->compressed_stripe);
      act_job->compressed_stripe=NULL;
      }
    if (act_job->stripe) {
      dumper_free(act_job->dynamic_area,
                  act_job->stripe);
      act_job->stripe=NULL;
      }
    if (act_job->preconverted_line) {
      dumper_free(act_job->dynamic_area,
                  act_job->preconverted_line);
      act_job->preconverted_line=NULL;
      }
    if (act_job->stripe_line_filled) {
      dumper_free(act_job->dynamic_area,
                  act_job->stripe_line_filled);
      act_job->stripe_line_filled=NULL;
      }
    if (act_job->max_stripe_usage_position) {
      dumper_free(act_job->dynamic_area,
                  act_job->max_stripe_usage_position);
      act_job->max_stripe_usage_position=NULL;
      }
    if (act_job->first_page_line) {
      dumper_free(act_job->dynamic_area,
                  act_job->first_page_line);
      act_job->first_page_line=NULL;
      }
    /* Evaluate command string at end of dumper */
    execute_control_string(&act_job->line_return,
                           &act_job->environment);
    if (act_job->line_end) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_end);
      act_job->line_end=NULL;
      }
    if (act_job->line_pass) {
      dumper_free(act_job->dynamic_area,
                  act_job->line_pass);
      act_job->line_pass=NULL;
      }
    drop_search_range(&act_job->colour_search);
    drop_stack(&act_job->environment);
    dynamic_area=act_job->dynamic_area;
    dumper_free(act_job->dynamic_area,
                act_job);
    dumper_dynamic_area_release(dynamic_area);
    }
  }
return TRUE;
}

/* This procedure is called from the assembler adapter and
   switches the actions requests of the RISCOS Dumper Driver
   to the according local procedures */
_kernel_oserror *printer_driver_handler(int *regs,
                                        void *pw)
{
/* Attention:
   r0-r11 are saved by assembler adapter on stack.
   Unfortunately _kernel_swi_regs is defined for
   registers 0-9 but the pointer is correct
   so use it directly */

#ifdef DEBUG_MODE
if ((common.magic1!=12345) ||
    (common.magic2!=67890)) {
  common.error_os.errnum=0;
  sprintf(common.error_os.errmess, "common damaged! %d, %d (Operations %d, %d)", common.magic1, common.magic2, common.last_op, regs[11]);
  return &common.error_os;
  }
common.last_op=regs[11];
#endif
switch(regs[11]) {
  case PDUMPERREASON_SETDRIVER: {
    /* Remark:
       reg 4 is pointing to a data block indeed but only to 256 bytes.
       Bytes 256 - 278 are not available at this point. */
    set_driver((unsigned char *) regs[4],
               (unsigned char *) regs[6],
               (unsigned long) regs[5]);
    }
  break;
  case PDUMPERREASON_OUTPUTDUMP: {
    output_dump(*((struct job_struct **) regs[8]),
                regs[1],
                (unsigned char *) regs[0],
                regs[3],
                regs[5],
                regs[4],
                regs[2]);
    }
  break;
  case PDUMPERREASON_COLOURSET: {
    regs[3]=translate_colour(regs[0],
                             regs[2]);
    }
  break;
  case PDUMPERREASON_STARTPAGE: {
    regs[0]=1;
    if ((regs[3]=start_page(*((struct job_struct **) regs[4]),
                            regs[1],
                            regs[6],
                            regs[3],
                            regs[7] & 0x0000FFFF,
                            (regs[7] >> 16) & 0x0000FFFF,
                            &regs[0],
                            regs[2])) < 0) {
      if (regs[3] == -1) {
        regs[3]=0;
        common.error_os.errnum=0;
        strcpy(common.error_os.errmess, "Invalid print job reference!");
        return &common.error_os;
        }
      else {
        regs[3]=0;
        common.error_os.errnum=0;
        strcpy(common.error_os.errmess, "Can't reserve page print job space!");
        return &common.error_os;
        }
      }
    }
  break;
  case PDUMPERREASON_ENDPAGE: {
    end_page(*((struct job_struct **) regs[3]),
             regs[1]);
    }
  break;
  case PDUMPERREASON_STARTJOB: {
    int error_code;

    /* Warning:
       Heavy Bug inside RISCOS-Manuals:
       reg 5 is not containing a pointer to the PDumper-Definitions */
    if ((*((struct job_struct **) regs[0])=start_job(regs[2],
                                                     &error_code,
                                                     regs[1])) == NULL) {
      if (error_code == -1) {
        common.error_os.errnum=0;
        strcpy(common.error_os.errmess, "Can't reserve print job space!");
        return &common.error_os;
        }
      else if (error_code == -2) {
        common.error_os.errnum=0;
        strcpy(common.error_os.errmess, "Can't locate calibration file!");
        return &common.error_os;
        }
      else {
        common.error_os.errnum=0;
        strcpy(common.error_os.errmess, "Can't locate required default calibration!");
        return &common.error_os;
        }
      }
    }
  break;
  case PDUMPERREASON_ABORTJOB: {
    abort_job(*((struct job_struct **) regs[0]),
              regs[3]);
    }
  break;
  case PDUMPERREASON_MISCOP: {
    /* ignore */
    }
  break;
  }
return NULL;
}

_kernel_oserror *epson_printer_driver_install(char *cmd_tail,
                                              int podule_base,
                                              void *pw)
{
_kernel_swi_regs regs;

#ifdef DEBUG_MODE
common.magic1=12345;
common.magic2=67890;
common.last_op=-1;
#endif
common.job_number=0;
common.stack_trace_flag=FALSE;
common.dynamic_area=dumper_dynamic_area_initialize(1500000);
if (!load_dither_information("<Printers$Dir>.Resources.PDumpers.PDumperEI.Ditherinfo",
                             common.dynamic_area,
                             &common.dither_line_offset)) {
  if (!common.dither_line_offset) {
    common.error_os.errnum=0;
    sprintf(common.error_os.errmess, "No Memory for dither information");
    return &common.error_os;
    }
  else {
    common.error_os.errnum=0;
    sprintf(common.error_os.errmess, "No Ditherinfo File");
    return &common.error_os;
    }
  }
/* Register the Dumper */
regs.r[0]=0x80000000;
regs.r[1]=PRINTER_DUMPER_NUMBER;
regs.r[2]=449;
regs.r[3]=(int) pw;
regs.r[4]=(int) printer_driver_handler_adap;
regs.r[5]=0x000000FF;
regs.r[6]=0x00000037;
regs.r[8]=PRINTER_DRIVER;
_kernel_swi(PDriver_MiscOpForDriver, &regs, &regs);
return NULL;
}

_kernel_oserror *epson_printer_driver_deinstall(char *cmd_tail,
                                                int podule_base,
                                                void *pw)
{
_kernel_swi_regs regs;

dumper_dynamic_area_release(common.dynamic_area);
/* Deregister the Dumper */
regs.r[0]=0x80000001;
regs.r[1]=PRINTER_DUMPER_NUMBER;
regs.r[8]=PRINTER_DRIVER;
_kernel_swi(PDriver_MiscOpForDriver, &regs, &regs);
return NULL;
}

void service_printer_driver(int service_number,
                            _kernel_swi_regs *dregs,
                            void *pw)
{
_kernel_swi_regs regs;

switch(service_number) {
  case SERVICE_PDUMPERSTARTING: {
    /* Register the Dumper */
    regs.r[0]=0x80000000;
    regs.r[1]=PRINTER_DUMPER_NUMBER;
    regs.r[2]=449;
    regs.r[3]=(int) pw;
    regs.r[4]=(int) printer_driver_handler_adap;
    regs.r[5]=0x000000FF;
    regs.r[6]=0x00000037;
    regs.r[8]=PRINTER_DRIVER;
    _kernel_swi(PDriver_MiscOpForDriver, &regs, &regs);
    }
  break;
  case SERVICE_PDUMPERDYING: {
    /* Deregister the Dumper */
    regs.r[0]=0x80000001;
    regs.r[1]=PRINTER_DUMPER_NUMBER;
    regs.r[8]=PRINTER_DRIVER;
    _kernel_swi(PDriver_MiscOpForDriver, &regs, &regs);
    }
  break;
  }
}

_kernel_oserror *epson_printer_driver_commands(char *arg_string,
                                               int argc,
                                               int cmd_no,
                                               void *pw)
{
char *c;

switch(cmd_no) {
  case 0: {
    if (argc == 1) {
      c=arg_string;
      /* lower case */
      while(*c != '\0') {
        if ((*c == '\n') ||
            (*c == '\r')) {
          *c='\0';
          }
        else {
          *c=tolower(*c);
          c++;
          }
        }
      if (strcmp(arg_string, "off") == 0) {
        common.stack_trace_flag=FALSE;
        }
      else if (strcmp(arg_string, "on") == 0) {
        common.stack_trace_flag=TRUE;
        }
      else {
        common.error_os.errnum=0;
        sprintf(common.error_os.errmess, "Syntax\tTraceCellarStack [on|off]");
        return &common.error_os;
        }
      }
    else {
      if (common.stack_trace_flag) {
        printf("on\n");
        }
      else {
        printf("off\n");
        }
      }
    }
  break;
  }
return NULL;
}
